﻿/*------------------------------------------------------------------------

CXXLWCSPBRK.HPP v3.6

Copyright 楊志賢 CxxlMan, 2008 - 2012
All Rights Reserved

1. 可找出多個分割或識別文字的位置
2. 可依不同的狀態指定不一樣的識別文字
3. 只可處理 Unicode 字串
4. 不影響原始來源字串

------------------------------------------------------------------------*/

#if !defined(__CXXLWCSPBRK_HPP_CxxlMan)
#define __CXXLWCSPBRK_HPP_CxxlMan

#include <string>
#include <sstream>
#include "SMART_STRING.HPP"

#if defined(_CXXLOBJECT_DLLEXPORT)
#define CXXLOBJECT_DLLEXPORT CXXL_DLLEXPORT
#else
#define CXXLOBJECT_DLLEXPORT CXXL_DLLIMPORT
#endif


namespace CxxlMan
{

class CXXLOBJECT_DLLEXPORT cxxlWcspbrk;

// cxxlWcspbrk 用的資料源介面
class CXXLOBJECT_DLLEXPORT IWcspbrkSource:virtual public cxxlObject
{
  // 索取指定長度的字串，回覆實際取得的長度
  virtual size_t cxxlFASTCALL GetStr(wchar_t *Dest,size_t Len) = 0;

public:
  // Constructor
  IWcspbrkSource(ISpirit *spirit = Spirit_Easy)
    :cxxlObject(spirit)
  {}

  // Destructor
  virtual ~IWcspbrkSource()
  {}

  friend class cxxlWcspbrk;
};


// cxxlWcspbrk::Next() 用來回報結果的結構
struct cxxlWcspbrk_Result
{
  UNICODE_String SubStr;  // 符合 tokens 或 NULL 之前的字句片斷
  UNICODE_String Token; // 符合的標記字串，無符合則 NULL

  cxxlWcspbrk_Result(const UNICODE_String &_SubStr, const UNICODE_String &_Token)
    :SubStr(_SubStr),
    Token(_Token)
  {
  }
  cxxlWcspbrk_Result()
  {
  }
  cxxlWcspbrk_Result(const cxxlWcspbrk_Result &Src)
  {
    SubStr = Src.SubStr;
    Token = Src.Token;
  }
  cxxlWcspbrk_Result& operator = (const cxxlWcspbrk_Result &Src)
  {
    SubStr = Src.SubStr;
    Token = Src.Token;
    return *this;
  }

};

// cxxlWcspbrk::XNext() 用來回報結果的結構
struct cxxlWcspbrk_XResult
{
  UNICODE_String SubStr;  // 不符合 tokens 或 NULL 之前的字句片斷
  bool isNULL; // 已讀至 NULL (讀取完了) 為 true

  cxxlWcspbrk_XResult(const UNICODE_String &_SubStr, bool _isNULL)
    :SubStr(_SubStr)
  {
    isNULL = _isNULL;
  }
  cxxlWcspbrk_XResult(const cxxlWcspbrk_XResult &Src)
  {
    SubStr = Src.SubStr;
    isNULL = Src.isNULL;
  }
  cxxlWcspbrk_XResult& operator = (const cxxlWcspbrk_XResult &Src)
  {
    SubStr = Src.SubStr;
    isNULL = Src.isNULL;
    return *this;
  }
};

class CXXLOBJECT_DLLEXPORT cxxlWcspbrk:virtual public cxxlObject
{
  CxxlMan::Smart_Ptr<IWcspbrkSource> Src; // 待搜尋的字串資料來源

  wchar_t *pBuff; // ring buffering，空間個數 256
  unsigned char Buff_HalfLen;
  unsigned char Buff_StrFs; // 在 pBuff 中要比對的開始位置
  unsigned char Buff_StrFsFlag; // Buff_StrFs 位於前半段為 0，否則為 1

  int OverPoint; // 從資料源讀取完時，用來設定結束位置，一開始指定在 -1

  // 調整 Buff_StrFs 和 RetValue
  void cxxlFASTCALL UpdateStrFs(unsigned int Shift);

  bool cxxlFASTCALL Compare(const wchar_t *Tok) const;

  bool cxxlFASTCALL isOver() const;


public:

  // Constructor
  cxxlWcspbrk(const Smart_Ptr<IWcspbrkSource> &psts,ISpirit *spirit = Spirit_Easy);

  // Destructor
  virtual ~cxxlWcspbrk();

  // 截取下一個符合 tokens 或 NULL 之前的字句片斷
  // tokens 是一個二維的字串，越前面的越先批配，每個字串的長度不能超過 128 個字
  // 元，最後須指定 NULL 以作為結尾識別
  // 例子：
  //
  //  const wchar_t *tokens[] = {L"\r\n",L"\n",L"\r",NULL};
  //
  cxxlWcspbrk_Result cxxlFASTCALL Next(const wchar_t *tokens[]);

  // 略過 tokens 包含的字串，直到不符合或 NULL 為止，並截取下一個不符合 tokens 或 NULL 之前的字句片斷
  // tokens 是一個二維的字串，越前面的越先批配，每個字串的長度不能超過 128 個字
  // 元，最後須指定 NULL 以作為結尾識別
  // 例子：
  //
  //  const wchar_t *tokens[] = {L"\r\n",L"\n",L"\r",NULL};
  //
  cxxlWcspbrk_XResult cxxlFASTCALL XNext(const wchar_t *skips[]);

};


// cxxlWcspbrk 用的資料源
// 只包裹 wchar_t 來源字串
class CXXLOBJECT_DLLEXPORT UnicodeStr_Source:public IWcspbrkSource
{
  CxxlMan::UNICODE_String m_StrSrc;
  size_t StrSrcBase;

  // 來自 IWcspbrkSource 須實作的虛擬函數
  size_t cxxlFASTCALL GetStr(wchar_t *Dest,size_t Len);

public:

  // Constructor
  UnicodeStr_Source(const CxxlMan::UNICODE_String &StrSrc, ISpirit *spirit = Spirit_Easy);
};

// cxxlWcspbrk 用的資料源
// 包裹 wistream
class wiStream_Source:public IWcspbrkSource
{
  std::wistream &WIn;

  // 來自 IWcspbrkSource 須實作的虛擬函數
  size_t cxxlFASTCALL GetStr(wchar_t *Dest,size_t Len)
  {
    WIn.read(Dest,Len);
    return WIn.gcount();
  }

public:

  // Constructor
  wiStream_Source(std::wistream &win, ISpirit *spirit = Spirit_Easy)
    :cxxlObject(spirit),IWcspbrkSource(spirit), WIn(win)
  {
  }
};


/*
** 從 StrSrc 找出 Srch 並換成 Rplc 相對應的字串，所以兩者的個數要一樣
** Srch 和 Rplc 要像以下這樣，最後須指定 NULL 以作為結尾識別，
** Srch 每個字串的長度不能超過 128 個字元，越前面的越先批配
**
**  const wchar_t *strs[] = {L"abc1234",L"abc",L"fdsa",NULL};
*/
CXXLOBJECT_DLLEXPORT UNICODE_String cxxlFASTCALL cxxlWcsReplace(const CxxlMan::UNICODE_String &StrSrc, const wchar_t *Srch[],const wchar_t *Rplc[]);




}   /* namespace CxxlMan */

#endif
